<!DOCTYPE html>



  


<html class="theme-next pisces use-motion" lang="zh-Hans">
<head><meta name="generator" content="Hexo 3.8.0">
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="theme-color" content="#222">

<script>
    (function () {
        if ('') {
            if (prompt('请输入文章密码') !== '') {
                alert('密码错误！');
                if (history.length === 1) {
                    location.replace("https://xczhello.gitee.io/"); // 这里替换成你的首页
                } else {
                    history.back();
                }
            }
        }
    })();
</script>








<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css">







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css">

<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/favicon.jpg?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon.jpg?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon.jpg?v=5.1.4">






  <meta name="keywords" content="Hexo, NexT">










<meta name="description" content="1. 通信类  1. 通信类 1.1. 同源策略及限制 1.2. 前后端如何通信 1.3. 如何创建 Ajax 1.3.1. XMLHTTPRequest 对象的工作流程 1.3.2. 发送 get 请求和 post 请求 1.3.3. onreadystatechange 事件 1.3.4. 兼容性处理 1.3.5. 事件的触发条件 1.3.6. 事件的触发顺序 1.3.7. 原生 Ajax 请">
<meta property="og:type" content="article">
<meta property="og:title" content="我的博客">
<meta property="og:url" content="https://xczhello.gitee.io/uncategorized/imooc-frontend-interview/7. 跨域通信类.html/index.html">
<meta property="og:site_name" content="我的博客">
<meta property="og:description" content="1. 通信类  1. 通信类 1.1. 同源策略及限制 1.2. 前后端如何通信 1.3. 如何创建 Ajax 1.3.1. XMLHTTPRequest 对象的工作流程 1.3.2. 发送 get 请求和 post 请求 1.3.3. onreadystatechange 事件 1.3.4. 兼容性处理 1.3.5. 事件的触发条件 1.3.6. 事件的触发顺序 1.3.7. 原生 Ajax 请">
<meta property="og:locale" content="zh-Hans">
<meta property="og:updated_time" content="2019-01-05T13:47:03.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="我的博客">
<meta name="twitter:description" content="1. 通信类  1. 通信类 1.1. 同源策略及限制 1.2. 前后端如何通信 1.3. 如何创建 Ajax 1.3.1. XMLHTTPRequest 对象的工作流程 1.3.2. 发送 get 请求和 post 请求 1.3.3. onreadystatechange 事件 1.3.4. 兼容性处理 1.3.5. 事件的触发条件 1.3.6. 事件的触发顺序 1.3.7. 原生 Ajax 请">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Pisces',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":true,"scrollpercent":true,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="https://xczhello.gitee.io/uncategorized/imooc-frontend-interview/7. 跨域通信类.html/">





  <title> | 我的博客</title>
  








</head>

<body itemscope="" itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <a href="https://github.com/Jem826" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewbox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"/><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"/><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"/></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>

    <header id="header" class="header" itemscope="" itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">我的博客</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br>
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br>
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br>
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br>
            
            归档
          </a>
        </li>
      
        
        <li class="menu-item menu-item-linkfriends">
          <a href="/linkfriends/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-link"></i> <br>
            
            友情链接
          </a>
        </li>
      
        
        <li class="menu-item menu-item-hot">
          <a href="/hot/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-fire"></i> <br>
            
            热点关注
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br>
            
            关于
          </a>
        </li>
      

      
        <li class="menu-item menu-item-search">
          
            <a href="javascript:;" class="popup-trigger">
          
            
              <i class="menu-item-icon fa fa-search fa-fw"></i> <br>
            
            搜索
          </a>
        </li>
      
    </ul>
  

  
    <div class="site-search">
      
  <div class="popup search-popup local-search-popup">
  <div class="local-search-header clearfix">
    <span class="search-icon">
      <i class="fa fa-search"></i>
    </span>
    <span class="popup-btn-close">
      <i class="fa fa-times-circle"></i>
    </span>
    <div class="local-search-input-wrapper">
      <input autocomplete="off" placeholder="搜索..." spellcheck="false" type="text" id="local-search-input">
    </div>
  </div>
  <div id="local-search-result"></div>
</div>



    </div>
  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope="" itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://xczhello.gitee.io/uncategorized/imooc-frontend-interview/7. 跨域通信类.html/">

    <span hidden itemprop="author" itemscope="" itemtype="http://schema.org/Person">
      <meta itemprop="name" content="Yomi">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/head.jpg">
    </span>

    <span hidden itemprop="publisher" itemscope="" itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="我的博客">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline"></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2019-03-06T17:48:34+08:00">
                2019-03-06
              </time>
            

            

            

            
          </span>

          

          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/uncategorized/imooc-frontend-interview/7. 跨域通信类.html/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count disqus-comment-count" data-disqus-identifier="uncategorized/imooc-frontend-interview/7. 跨域通信类.html/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          
            <span class="post-meta-divider">|</span>
            <span class="page-pv"><i class="fa fa-file-o"></i> 阅读数
            <span class="busuanzi-value" id="busuanzi_value_page_pv"></span>
            </span>
          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">字数统计&#58;</span>
                
                <span title="字数统计">
                  3.1k字
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                
                <span title="阅读时长">
                  13分钟
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <h1 id="1-通信类"><a href="#1-通信类" class="headerlink" title="1. 通信类"></a>1. 通信类</h1><!-- TOC -->
<ul>
<li><a href="#1-通信类">1. 通信类</a><ul>
<li><a href="#11-同源策略及限制">1.1. 同源策略及限制</a></li>
<li><a href="#12-前后端如何通信">1.2. 前后端如何通信</a></li>
<li><a href="#13-如何创建-ajax">1.3. 如何创建 Ajax</a><ul>
<li><a href="#131-xmlhttprequest-对象的工作流程">1.3.1. <code>XMLHTTPRequest</code> 对象的工作流程</a></li>
<li><a href="#132-发送-get-请求和-post-请求">1.3.2. 发送 get 请求和 post 请求</a></li>
<li><a href="#133-onreadystatechange-事件">1.3.3. <code>onreadystatechange</code> 事件</a></li>
<li><a href="#134-兼容性处理">1.3.4. 兼容性处理</a></li>
<li><a href="#135-事件的触发条件">1.3.5. 事件的触发条件</a></li>
<li><a href="#136-事件的触发顺序">1.3.6. 事件的触发顺序</a></li>
<li><a href="#137-原生-ajax-请求">1.3.7. 原生 Ajax 请求</a></li>
</ul>
</li>
<li><a href="#14-跨域通信的几种方式">1.4. 跨域通信的几种方式</a><ul>
<li><a href="#141-jsonp">1.4.1. JSONP</a></li>
<li><a href="#142-hash">1.4.2. Hash</a></li>
<li><a href="#143-postmessage">1.4.3. postMessage()</a></li>
<li><a href="#144-websocket">1.4.4. WebSocket</a></li>
<li><a href="#145-cors">1.4.5. CORS</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<!-- /TOC -->
<h2 id="1-1-同源策略及限制"><a href="#1-1-同源策略及限制" class="headerlink" title="1.1. 同源策略及限制"></a>1.1. 同源策略及限制</h2><p><strong>同源策略</strong>：限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。</p>
<p><strong>源</strong>：包括三个部分：协议、域名、端口（http 协议的默认端口是 80）。如果有任何一个部分不同，则源不同，那就是跨域了。</p>
<p><strong>限制</strong>：</p>
<ul>
<li>Cookie、LocalStorage 和 IndexDB 无法读取</li>
<li>DOM 无法获取</li>
<li>AJAX 请求不能发送</li>
</ul>
<h2 id="1-2-前后端如何通信"><a href="#1-2-前后端如何通信" class="headerlink" title="1.2. 前后端如何通信"></a>1.2. 前后端如何通信</h2><ol>
<li>Ajax：同源通信，不支持跨域</li>
<li>WebSocket：不受同源策略的限制，支持跨域。</li>
<li>CORS：不受同源策略的限制，支持跨域。一种新的通信协议标准。可以理解成是：同时支持同源和跨域的 Ajax。</li>
</ol>
<h2 id="1-3-如何创建-Ajax"><a href="#1-3-如何创建-Ajax" class="headerlink" title="1.3. 如何创建 Ajax"></a>1.3. 如何创建 Ajax</h2><h3 id="1-3-1-XMLHTTPRequest-对象的工作流程"><a href="#1-3-1-XMLHTTPRequest-对象的工作流程" class="headerlink" title="1.3.1. XMLHTTPRequest 对象的工作流程"></a>1.3.1. <code>XMLHTTPRequest</code> 对象的工作流程</h3><p>（1）创建 XMLHttpRequest 对象。</p>
<p>（2）使用 open 方法设置请求的参数。open(method, url, 是否异步)。</p>
<p>（3）发送请求。</p>
<p>（4）注册事件。 注册 onreadystatechange 事件，状态改变时就会调用。如果要在数据完整请求回来的时候才调用，我们需要手动写一些判断的逻辑。</p>
<p>（5）获取返回的数据，更新 UI。</p>
<h3 id="1-3-2-发送-get-请求和-post-请求"><a href="#1-3-2-发送-get-请求和-post-请求" class="headerlink" title="1.3.2. 发送 get 请求和 post 请求"></a>1.3.2. 发送 get 请求和 post 请求</h3><p><strong>get 请求</strong>：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Document<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>Ajax 发送 get 请求<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"button"</span> <span class="attr">value</span>=<span class="string">"发送get_ajax请求"</span> <span class="attr">id</span>=<span class="string">'btnAjax'</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">// 绑定点击事件</span></span></span><br><span class="line"><span class="javascript">    <span class="built_in">document</span>.querySelector(<span class="string">'#btnAjax'</span>).onclick = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">        <span class="comment">// 发送ajax 请求 需要 五步</span></span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">        <span class="comment">// 1. 创建异步对象</span></span></span><br><span class="line"><span class="javascript">        <span class="keyword">var</span> ajaxObj = <span class="keyword">new</span> XMLHttpRequest();</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">        <span class="comment">// 2. 设置请求的参数。包括：请求的方法、请求的url。</span></span></span><br><span class="line"><span class="javascript">        ajaxObj.open(<span class="string">'get'</span>, <span class="string">'02-ajax.php'</span>);</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">        <span class="comment">// 3. 发送请求</span></span></span><br><span class="line"><span class="undefined">        ajaxObj.send();</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">        <span class="comment">// 4. 注册事件。onreadystatechange事件，状态改变时就会调用。</span></span></span><br><span class="line"><span class="javascript">        <span class="comment">// 如果要在数据完整请求回来的时候才调用，我们需要手动写一些判断的逻辑。</span></span></span><br><span class="line"><span class="javascript">        ajaxObj.onreadystatechange = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="comment">// 为了保证数据完整返回，我们一般会判断两个值</span></span></span><br><span class="line"><span class="javascript">            <span class="keyword">if</span> (ajaxObj.readyState == <span class="number">4</span> &amp;&amp; ajaxObj.status == <span class="number">200</span>) &#123;</span></span><br><span class="line"><span class="javascript">                <span class="comment">// 如果能够进到这个判断说明数据完美的回来了，并且请求的页面是存在的</span></span></span><br><span class="line"><span class="javascript">                <span class="comment">// 5. 在注册的事件中获取返回的内容，并修改页面的显示</span></span></span><br><span class="line"><span class="javascript">                <span class="built_in">console</span>.log(<span class="string">'数据返回成功'</span>);</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">                <span class="comment">// 数据是保存在异步对象的属性中</span></span></span><br><span class="line"><span class="javascript">                <span class="built_in">console</span>.log(ajaxObj.responseText);</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">                <span class="comment">// 修改页面的显示</span></span></span><br><span class="line"><span class="javascript">                <span class="built_in">document</span>.querySelector(<span class="string">'h1'</span>).innerHTML = ajaxObj.responseText;</span></span><br><span class="line"><span class="undefined">            &#125;</span></span><br><span class="line"><span class="undefined">        &#125;</span></span><br><span class="line"><span class="undefined">    &#125;</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p><strong>post 请求</strong>：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>Document<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>Ajax 发送 get 请求<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"button"</span> <span class="attr">value</span>=<span class="string">"发送put_ajax请求"</span> <span class="attr">id</span>=<span class="string">'btnAjax'</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">"text/javascript"</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">// 1. 异步对象</span></span></span><br><span class="line"><span class="javascript">    <span class="keyword">var</span> xhr = <span class="keyword">new</span> XMLHttpRequest();</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">// 2. 设置属性</span></span></span><br><span class="line"><span class="javascript">    xhr.open(<span class="string">'post'</span>, <span class="string">'02.post.php'</span>);</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">// 3. 如果想要使用post提交数据,必须添加此行</span></span></span><br><span class="line"><span class="javascript">    xhr.setRequestHeader(<span class="string">"Content-type"</span>, <span class="string">"application/x-www-form-urlencoded"</span>);</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">// 4. 将数据通过send方法传递</span></span></span><br><span class="line"><span class="javascript">    xhr.send(<span class="string">'name=fox&amp;age=18'</span>);</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">// 5. 发送并接受返回值</span></span></span><br><span class="line"><span class="javascript">    xhr.onreadystatechange = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">        <span class="comment">// 这步为判断服务器是否正确响应</span></span></span><br><span class="line"><span class="javascript">        <span class="keyword">if</span> (xhr.readyState == <span class="number">4</span> &amp;&amp; xhr.status == <span class="number">200</span>) &#123;</span></span><br><span class="line"><span class="undefined">            alert(xhr.responseText);</span></span><br><span class="line"><span class="undefined">        &#125;</span></span><br><span class="line"><span class="undefined">    &#125;;</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="1-3-3-onreadystatechange-事件"><a href="#1-3-3-onreadystatechange-事件" class="headerlink" title="1.3.3. onreadystatechange 事件"></a>1.3.3. <code>onreadystatechange</code> 事件</h3><p>注册 <code>onreadystatechange</code> 事件后，每当 <code>readyState</code> 属性改变时，就会调用 <code>onreadystatechange</code> 函数。</p>
<p><code>readyState</code>：（存有 <code>XMLHttpRequest</code> 的状态。从 0 到 4 发生变化）</p>
<p>0: 请求未初始化。尚未调用 open()方法</p>
<p>1: 服务器连接已建立。已经调用 open()方法，未调用 send()方法</p>
<p>2: 请求已接收。已经调用 send()方法，但尚未接受到响应</p>
<p>3: 请求处理中</p>
<p>4: 请求已完成，且响应已就绪</p>
<h3 id="1-3-4-兼容性处理"><a href="#1-3-4-兼容性处理" class="headerlink" title="1.3.4. 兼容性处理"></a>1.3.4. 兼容性处理</h3><p>IE8/IE9、Opera Mini 完全不支持 xhr 对象</p>
<p>IE10/IE11 部分支持，不支持 xhr.responseType 为 json</p>
<p>部分浏览器不支持设置请求超时，即无法使用 xhr.timeout</p>
<p>部分浏览器不支持 xhr.responseType 为 blob</p>
<h3 id="1-3-5-事件的触发条件"><a href="#1-3-5-事件的触发条件" class="headerlink" title="1.3.5. 事件的触发条件"></a>1.3.5. 事件的触发条件</h3><table>
<thead>
<tr>
<th>事件</th>
<th>触发条件</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>onreadystatechange</code></td>
<td>每当 <code>xhr.readyState</code> 改变时触发；但 <code>xhr.readyState</code>由非 0 值变为 0 时不触发。</td>
</tr>
<tr>
<td><code>onloadstart</code></td>
<td>调用 <code>xhr.send()</code>方法后立即触发，若 <code>xhr.send()</code>未被调用则不会触发此事件。</td>
</tr>
<tr>
<td><code>onprogress</code></td>
<td><code>xhr.upload.onprogress</code> 在上传阶段(即 <code>xhr.send()</code>之后，<code>xhr.readystate=2</code> 之前)触发，每 50ms 触发一次；<code>xhr.onprogress</code> 在下载阶段（即 <code>xhr.readystate=3</code> 时）触发，每 50ms 触发一次。</td>
</tr>
<tr>
<td><code>onload</code></td>
<td>当请求成功完成时触发，此时 <code>xhr.readystate=4</code></td>
</tr>
<tr>
<td><code>onloadend</code></td>
<td>当请求结束（包括请求成功和请求失败）时触发</td>
</tr>
<tr>
<td><code>onabort</code></td>
<td>当调用 <code>xhr.abort()</code>后触发</td>
</tr>
<tr>
<td><code>ontimeout</code></td>
<td><code>xhr.timeout</code> 不等于 0，由请求开始即 <code>onloadstart</code> 开始算起，当到达 <code>xhr.timeout</code> 所设置时间请求还未结束即 <code>onloadend</code>，则触发此事件。</td>
</tr>
<tr>
<td><code>onerror</code></td>
<td>在请求过程中，若发生 <code>Network error</code> 则会触发此事件（若发生 <code>Network error</code> 时，上传还没有结束，则会先触发 <code>xhr.upload.onerror</code>，再触发 <code>xhr.onerror</code>；若发生 <code>Network error</code> 时，上传已经结束，则只会触发 <code>xhr.onerror</code>）。注意，只有发生了网络层级别的异常才会触发此事件，对于应用层级别的异常，如响应返回的 <code>xhr.statusCode</code> 是 4xx 时，并不属于 <code>Network error</code>，所以不会触发 <code>onerror</code> 事件，而是会触发 <code>onload</code> 事件。</td>
</tr>
</tbody>
</table>
<h3 id="1-3-6-事件的触发顺序"><a href="#1-3-6-事件的触发顺序" class="headerlink" title="1.3.6. 事件的触发顺序"></a>1.3.6. 事件的触发顺序</h3><p>当请求一切正常时，相关的事件触发顺序如下：</p>
<ol>
<li><p>触发 xhr.onreadystatechange(之后每次 readyState 变化时，都会触发一次)</p>
</li>
<li><p>触发 xhr.onloadstart<br>//上传阶段开始：</p>
</li>
<li><p>触发 xhr.upload.onloadstart</p>
</li>
<li><p>触发 xhr.upload.onprogress</p>
</li>
<li><p>触发 xhr.upload.onload</p>
</li>
<li><p>触发 xhr.upload.onloadend<br>//上传结束，下载阶段开始：</p>
</li>
<li><p>触发 xhr.onprogress</p>
</li>
<li><p>触发 xhr.onload</p>
</li>
<li><p>触发 xhr.onloadend</p>
</li>
</ol>
<h3 id="1-3-7-原生-Ajax-请求"><a href="#1-3-7-原生-Ajax-请求" class="headerlink" title="1.3.7. 原生 Ajax 请求"></a>1.3.7. 原生 Ajax 请求</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> util = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">  <span class="comment">//获取 ajax 请求之后的json</span></span><br><span class="line">  util.json = <span class="function"><span class="keyword">function</span> (<span class="params">options</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">var</span> opt = &#123;</span><br><span class="line">          url: <span class="string">''</span>,</span><br><span class="line">          type: <span class="string">'get'</span>,</span><br><span class="line">          data: &#123;&#125;,</span><br><span class="line">          success: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">          &#125;,</span><br><span class="line">          error: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">          &#125;,</span><br><span class="line"></span><br><span class="line">      &#125;;</span><br><span class="line">      util.extend(opt, options);</span><br><span class="line">      <span class="keyword">if</span> (opt.url) &#123;</span><br><span class="line">          <span class="comment">//IE兼容性处理：浏览器特征检查。检查该浏览器是否存在XMLHttpRequest这个api，没有的话，就用IE的api</span></span><br><span class="line">          <span class="keyword">var</span> xhr = XMLHttpRequest ? <span class="keyword">new</span> XMLHttpRequest() : <span class="keyword">new</span> <span class="built_in">window</span>.ActiveXObject(<span class="string">'Microsoft.XMLHTTP'</span>);</span><br><span class="line"></span><br><span class="line">          <span class="keyword">var</span> data = opt.data,</span><br><span class="line">              url = opt.url,</span><br><span class="line">              type = opt.type.toUpperCase();</span><br><span class="line">          dataArr = [];</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">var</span> key <span class="keyword">in</span> data) &#123;</span><br><span class="line">          dataArr.push(key + <span class="string">'='</span> + data[key]);</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (type === <span class="string">'GET'</span>) &#123;</span><br><span class="line">          url = url + <span class="string">'?'</span> + dataArr.join(<span class="string">'&amp;'</span>);</span><br><span class="line">          xhr.open(type, url.replace(<span class="regexp">/\?$/g</span>, <span class="string">''</span>), <span class="literal">true</span>);</span><br><span class="line">          xhr.send();</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (type === <span class="string">'POST'</span>) &#123;</span><br><span class="line">          xhr.open(type, url, <span class="literal">true</span>);</span><br><span class="line">          <span class="comment">// 如果想要使用post提交数据,必须添加此行</span></span><br><span class="line">          xhr.setRequestHeader(<span class="string">"Content-type"</span>, <span class="string">"application/x-www-form-urlencoded"</span>);</span><br><span class="line">          xhr.send(dataArr.join(<span class="string">'&amp;'</span>));</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      xhr.onload = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">          <span class="keyword">if</span> (xhr.status === <span class="number">200</span> || xhr.status === <span class="number">304</span>) &#123; <span class="comment">//304表示：用缓存即可。206表示获取媒体资源的前面一部分</span></span><br><span class="line">              <span class="keyword">var</span> res;</span><br><span class="line">              <span class="keyword">if</span> (opt.success &amp;&amp; opt.success <span class="keyword">instanceof</span> <span class="built_in">Function</span>) &#123;</span><br><span class="line">                  res = xhr.responseText;</span><br><span class="line">                  <span class="keyword">if</span> (<span class="keyword">typeof</span> res === <span class="string">'string'</span>) &#123;</span><br><span class="line">                      res = <span class="built_in">JSON</span>.parse(res);  <span class="comment">//将字符串转成json</span></span><br><span class="line">                      opt.success.call(xhr, res);</span><br><span class="line">                  &#125;</span><br><span class="line">              &#125;</span><br><span class="line">          &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">              <span class="keyword">if</span> (opt.error &amp;&amp; opt.error <span class="keyword">instanceof</span> <span class="built_in">Function</span>) &#123;</span><br><span class="line">                  opt.error.call(xhr, res);</span><br><span class="line">              &#125;</span><br><span class="line">          &#125;</span><br><span class="line">      &#125;;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>
<h2 id="1-4-跨域通信的几种方式"><a href="#1-4-跨域通信的几种方式" class="headerlink" title="1.4. 跨域通信的几种方式"></a>1.4. 跨域通信的几种方式</h2><h3 id="1-4-1-JSONP"><a href="#1-4-1-JSONP" class="headerlink" title="1.4.1. JSONP"></a>1.4.1. JSONP</h3><p>在 CORS 和 postMessage 以前，我们一直都是通过 JSONP 来做跨域通信的。</p>
<p><strong>JSONP 的原理</strong>：</p>
<p>通过<code>&lt;script&gt;</code>标签的异步加载来实现的。比如说，实际开发中，我们发现，head 标签里，可以通过<code>&lt;script&gt;</code>标签的 src，里面放 url，加载很多在线的插件。这就是用到了 JSONP。</p>
<p><strong>优点</strong>：浏览器兼容性好，服务器改造工作量小。</p>
<p><strong>缺点</strong>：仅适用 GET 请求；请求出错时，无法获得 http 错误状态码</p>
<p><strong>JSONP 的实现</strong>：</p>
<p>比如说，客户端这样写：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;script src=<span class="string">"http://www.smyhvae.com/?data=name&amp;callback=myjsonp"</span>&gt;<span class="xml"><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br></pre></td></tr></table></figure>
<p>上面的 src 中，data=name 是 get 请求的参数，myjsonp 是和后台约定好的函数名。<br>服务器端这样写：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">myjsonp(&#123;</span><br><span class="line">    data: &#123;&#125;</span><br><span class="line"></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<p>于是，本地要求创建一个 myjsonp 的全局函数，才能将返回的数据执行出来。</p>
<p><strong>实际开发中，前端的 JSONP 是这样实现的</strong>：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> util = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//定义方法：动态创建 script 标签</span></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * [function 在页面中注入js脚本]</span></span><br><span class="line"><span class="comment">     * @param  &#123;[type]&#125; url     [description]</span></span><br><span class="line"><span class="comment">     * @param  &#123;[type]&#125; charset [description]</span></span><br><span class="line"><span class="comment">     * @return &#123;[type]&#125;         [description]</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    util.createScript = <span class="function"><span class="keyword">function</span> (<span class="params">url, charset</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">var</span> script = <span class="built_in">document</span>.createElement(<span class="string">'script'</span>);</span><br><span class="line">        script.setAttribute(<span class="string">'type'</span>, <span class="string">'text/javascript'</span>);</span><br><span class="line">        charset &amp;&amp; script.setAttribute(<span class="string">'charset'</span>, charset);</span><br><span class="line">        script.setAttribute(<span class="string">'src'</span>, url);</span><br><span class="line">        script.async = <span class="literal">true</span>;</span><br><span class="line">        <span class="keyword">return</span> script;</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * [function 处理jsonp]</span></span><br><span class="line"><span class="comment">     * @param  &#123;[type]&#125; url      [description]</span></span><br><span class="line"><span class="comment">     * @param  &#123;[type]&#125; onsucess [description]</span></span><br><span class="line"><span class="comment">     * @param  &#123;[type]&#125; onerror  [description]</span></span><br><span class="line"><span class="comment">     * @param  &#123;[type]&#125; charset  [description]</span></span><br><span class="line"><span class="comment">     * @return &#123;[type]&#125;          [description]</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    util.jsonp = <span class="function"><span class="keyword">function</span> (<span class="params">url, onsuccess, onerror, charset</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">var</span> callbackName = util.getName(<span class="string">'tt_player'</span>); <span class="comment">//事先约定好的 函数名</span></span><br><span class="line">        <span class="built_in">window</span>[callbackName] = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;      <span class="comment">//根据回调名称注册一个全局的函数</span></span><br><span class="line">            <span class="keyword">if</span> (onsuccess &amp;&amp; util.isFunction(onsuccess)) &#123;</span><br><span class="line">                onsuccess(<span class="built_in">arguments</span>[<span class="number">0</span>]);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="keyword">var</span> script = util.createScript(url + <span class="string">'&amp;callback='</span> + callbackName, charset);   <span class="comment">//动态创建一个script标签</span></span><br><span class="line">        script.onload = script.onreadystatechange = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;   <span class="comment">//监听加载成功的事件，获取数据</span></span><br><span class="line">            <span class="keyword">if</span> (!script.readyState || <span class="regexp">/loaded|complete/</span>.test(script.readyState)) &#123;</span><br><span class="line">                script.onload = script.onreadystatechange = <span class="literal">null</span>;</span><br><span class="line">                <span class="comment">// 移除该script的 DOM 对象</span></span><br><span class="line">                <span class="keyword">if</span> (script.parentNode) &#123;</span><br><span class="line">                    script.parentNode.removeChild(script);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// 删除函数或变量</span></span><br><span class="line">                <span class="built_in">window</span>[callbackName] = <span class="literal">null</span>;  <span class="comment">//最后不要忘了删除</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        script.onerror = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">            <span class="keyword">if</span> (onerror &amp;&amp; util.isFunction(onerror)) &#123;</span><br><span class="line">                onerror();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="built_in">document</span>.getElementsByTagName(<span class="string">'head'</span>)[<span class="number">0</span>].appendChild(script); <span class="comment">//往html中增加这个标签，目的是把请求发送出去</span></span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">&lt;<span class="regexp">/script&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="1-4-2-Hash"><a href="#1-4-2-Hash" class="headerlink" title="1.4.2. Hash"></a>1.4.2. Hash</h3><p>url 地址中<code>#</code>后面的内容叫 Hash，<strong>Hash 的改变页面是不刷新的</strong>，这就是 Hash 做跨域通信的基本原理。<br>url 地址中<code>?</code>后面的内容叫 Search。Search 的改变，会导致页面刷新，因此不能做跨域通信。</p>
<p><strong>使用场景</strong>：我的页面 A 通过 iframe 或 frame 嵌入了跨域的页面 B。现在，我这个 A 页面想给 B 页面发消息，怎么操作呢？</p>
<p>（1）首先，在我的 A 页面中：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//伪代码</span></span><br><span class="line"><span class="keyword">var</span> B = <span class="built_in">document</span>.getElementsByTagName(<span class="string">'iframe'</span>);</span><br><span class="line">B.src = B.src + <span class="string">'#'</span> + <span class="string">'jsonString'</span>;  <span class="comment">//我们可以把JS 对象，通过 JSON.stringify()方法转成 json字符串，发给 B</span></span><br></pre></td></tr></table></figure>
<p>（2）然后，在 B 页面中：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// B中的伪代码</span></span><br><span class="line"><span class="built_in">window</span>.onhashchange = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;  <span class="comment">//通过onhashchange方法监听，url中的 hash 是否发生变化</span></span><br><span class="line">    <span class="keyword">var</span> data = <span class="built_in">window</span>.location.hash;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h3 id="1-4-3-postMessage"><a href="#1-4-3-postMessage" class="headerlink" title="1.4.3. postMessage()"></a>1.4.3. postMessage()</h3><p>html5 中新增的跨域通信方式，可解决 iframe &amp; window.open 的跨域问题</p>
<p><strong>使用场景</strong>：窗口 A (http:A.com)向跨域的窗口 B (http:B.com)发送信息。步骤如下。</p>
<p>（1）在 A 窗口中操作如下：向 B 窗口发送数据：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 窗口A(http:A.com)向跨域的窗口B(http:B.com)发送信息</span></span><br><span class="line">Bwindow.postMessage(<span class="string">'data'</span>, <span class="string">'http://B.com'</span>); <span class="comment">//这里强调的是B窗口里的window对象</span></span><br></pre></td></tr></table></figure>
<p>（2）在 B 窗口中操作如下：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 在窗口B中监听 message 事件</span></span><br><span class="line">Awindow.addEventListener(<span class="string">'message'</span>, <span class="function"><span class="keyword">function</span> (<span class="params">event</span>) </span>&#123;   <span class="comment">//这里强调的是A窗口里的window对象</span></span><br><span class="line">    <span class="built_in">console</span>.log(event.origin);  <span class="comment">//获取 ：url。这里指：http://A.com</span></span><br><span class="line">    <span class="built_in">console</span>.log(event.source);  <span class="comment">//获取：A window对象</span></span><br><span class="line">    <span class="built_in">console</span>.log(event.data);    <span class="comment">//获取传过来的数据</span></span><br><span class="line">&#125;, <span class="literal">false</span>);</span><br></pre></td></tr></table></figure>
<h3 id="1-4-4-WebSocket"><a href="#1-4-4-WebSocket" class="headerlink" title="1.4.4. WebSocket"></a>1.4.4. WebSocket</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> ws = <span class="keyword">new</span> WebSocket(<span class="string">'wss://echo.websocket.org'</span>);<span class="comment">// 创建WebSocket的对象。参数可以是 ws 或 wss，后者表示加密。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 把请求发出去</span></span><br><span class="line">ws.onopen = <span class="function"><span class="keyword">function</span> (<span class="params">evt</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'Connection open ...'</span>);</span><br><span class="line">    ws.send(<span class="string">'Hello WebSockets!'</span>);</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 对方发消息过来时，我接收</span></span><br><span class="line">ws.onmessage = <span class="function"><span class="keyword">function</span> (<span class="params">evt</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'Received Message: '</span>, evt.data);</span><br><span class="line">    ws.close();</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 关闭连接</span></span><br><span class="line">ws.onclose = <span class="function"><span class="keyword">function</span> (<span class="params">evt</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'Connection closed.'</span>);</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<h3 id="1-4-5-CORS"><a href="#1-4-5-CORS" class="headerlink" title="1.4.5. CORS"></a>1.4.5. CORS</h3><p>CORS 可以理解成是既可以同步、也可以异步的 Ajax。</p>
<p>fetch 是一个比较新的 API，用来实现 CORS 通信。用法如下：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// url（必选），options（可选）</span></span><br><span class="line">fetch(<span class="string">'/some/url/'</span>, &#123;</span><br><span class="line">    method: <span class="string">'get'</span>,</span><br><span class="line">&#125;).then(<span class="function"><span class="keyword">function</span> (<span class="params">response</span>) </span>&#123;  <span class="comment">//类似于 ES6中的promise</span></span><br><span class="line"></span><br><span class="line">&#125;).catch(<span class="function"><span class="keyword">function</span> (<span class="params">err</span>) </span>&#123;</span><br><span class="line">  <span class="comment">// 出错了，等价于 then 的第二个参数，但这样更好用更直观</span></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<p><strong>CORS 为什么支持跨域的通信</strong>？<br>跨域时，浏览器会拦截 Ajax 请求，并在 http 头中加 Origin。</p>
<p><strong>与 JSONP 的比较</strong>：</p>
<ul>
<li>CORS 与 JSONP 的使用目的相同，但是比 JSONP 更强大。</li>
<li>JSONP 只支持 GET 请求，CORS 支持所有类型的 HTTP 请求。JSONP 的优势在于支持老式浏览器，以及可以向不支持 CORS 的网站请求数据。</li>
</ul>

      
    </div>
    
    
    

    <div>
      
        <div>
    
        <div style="text-align:center;color: #ccc;font-size:14px;">-------------本文结束<i class="fa fa-paw"></i>感谢您的阅读-------------</div>
    
</div>

      
    </div>

    <div>
          
            


          
    </div>

    

    

    

    <footer class="post-footer">
      

      
      
        <div class="post-widgets">
        

        

        
          
          <div id="needsharebutton-postbottom">
            <span class="btn">
              <i class="fa fa-share-alt" aria-hidden="true"></i>
            </span>
          </div>
        
        </div>
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/uncategorized/imooc-frontend-interview/6. 类与继承.html/" rel="next" title="">
                <i class="fa fa-chevron-left"></i> 
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/uncategorized/imooc-frontend-interview/8. 安全问题：CSRF和XSS.html/" rel="prev" title="">
                 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  
    <div class="comments" id="comments">
      <div id="disqus_thread">
        <noscript>
          Please enable JavaScript to view the
          <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a>
        </noscript>
      </div>
    </div>

  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope="" itemtype="http://schema.org/Person">
            
              <img class="site-author-image" itemprop="image" src="/images/head.jpg" alt="Yomi">
            
              <p class="site-author-name" itemprop="name">Yomi</p>
              <p class="site-description motion-element" itemprop="description">--悟已往之不谏，知来者之可追--</p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/">
              
                  <span class="site-state-item-count">28</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/categories/index.html">
                  <span class="site-state-item-count">6</span>
                  <span class="site-state-item-name">分类</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                <a href="/tags/index.html">
                  <span class="site-state-item-count">5</span>
                  <span class="site-state-item-name">标签</span>
                </a>
              </div>
            

          </nav>

          

          
            <div class="links-of-author motion-element">
                
                  <span class="links-of-author-item">
                    <a href="https://github.com/Jem826" target="_blank" title="GitHub">
                      
                        <i class="fa fa-fw fa-github"></i>GitHub</a>
                  </span>
                
                  <span class="links-of-author-item">
                    <a href="https://www.jianshu.com" target="_blank" title="简书">
                      
                        <i class="fa fa-fw fa-heartbeat"></i>简书</a>
                  </span>
                
                  <span class="links-of-author-item">
                    <a href="https://juejin.im" target="_blank" title="掘金">
                      
                        <i class="fa fa-fw fa-gg-circle"></i>掘金</a>
                  </span>
                
                  <span class="links-of-author-item">
                    <a href="tencent://message/?uin=964325846&Site=个人QQ&Menu=yes" target="_blank" title="QQ">
                      
                        <i class="fa fa-fw fa-qq"></i>QQ</a>
                  </span>
                
            </div>
          

          
          

          
          
            <div class="links-of-blogroll motion-element links-of-blogroll-block">
              <div class="links-of-blogroll-title">
                <i class="fa  fa-fw fa-link"></i>
                推荐阅读
              </div>
              <ul class="links-of-blogroll-list">
                
                  <li class="links-of-blogroll-item">
                    <a href="http://www.uisdc.com/" title="优设" target="_blank">优设</a>
                  </li>
                
                  <li class="links-of-blogroll-item">
                    <a href="http://www.zhangxinxu.com/" title="张鑫旭" target="_blank">张鑫旭</a>
                  </li>
                
                  <li class="links-of-blogroll-item">
                    <a href="http://www.alloyteam.com/nav/" title="Web前端导航" target="_blank">Web前端导航</a>
                  </li>
                
                  <li class="links-of-blogroll-item">
                    <a href="http://www.36zhen.com/t?id=3448" title="前端书籍资料" target="_blank">前端书籍资料</a>
                  </li>
                
                  <li class="links-of-blogroll-item">
                    <a href="http://hao.shejidaren.com" title="设计导航" target="_blank">设计导航</a>
                  </li>
                
                  <li class="links-of-blogroll-item">
                    <a href="http://www.vipsheji.cn" title="设计网站大全" target="_blank">设计网站大全</a>
                  </li>
                
                  <li class="links-of-blogroll-item">
                    <a href="http://ife.baidu.com/" title="百度前端技术学院" target="_blank">百度前端技术学院</a>
                  </li>
                
                  <li class="links-of-blogroll-item">
                    <a href="http://wf.uisdc.com/cn/" title="google前端开发基础" target="_blank">google前端开发基础</a>
                  </li>
                
              </ul>
            </div>
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#1-通信类"><span class="nav-text">1. 通信类</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-1-同源策略及限制"><span class="nav-text">1.1. 同源策略及限制</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#1-2-前后端如何通信"><span class="nav-text">1.2. 前后端如何通信</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#1-3-如何创建-Ajax"><span class="nav-text">1.3. 如何创建 Ajax</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-1-XMLHTTPRequest-对象的工作流程"><span class="nav-text">1.3.1. XMLHTTPRequest 对象的工作流程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-2-发送-get-请求和-post-请求"><span class="nav-text">1.3.2. 发送 get 请求和 post 请求</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-3-onreadystatechange-事件"><span class="nav-text">1.3.3. onreadystatechange 事件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-4-兼容性处理"><span class="nav-text">1.3.4. 兼容性处理</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-5-事件的触发条件"><span class="nav-text">1.3.5. 事件的触发条件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-6-事件的触发顺序"><span class="nav-text">1.3.6. 事件的触发顺序</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-3-7-原生-Ajax-请求"><span class="nav-text">1.3.7. 原生 Ajax 请求</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#1-4-跨域通信的几种方式"><span class="nav-text">1.4. 跨域通信的几种方式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-4-1-JSONP"><span class="nav-text">1.4.1. JSONP</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-4-2-Hash"><span class="nav-text">1.4.2. Hash</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-4-3-postMessage"><span class="nav-text">1.4.3. postMessage()</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-4-4-WebSocket"><span class="nav-text">1.4.4. WebSocket</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#1-4-5-CORS"><span class="nav-text">1.4.5. CORS</span></a></li></ol></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      
        <div class="back-to-top">
          <i class="fa fa-arrow-up"></i>
          
            <span id="scrollpercent"><span>0</span>%</span>
          
        </div>
      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2019</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Yomi</span>

  
</div>

<!--

  <div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>




  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Pisces</a> v5.1.4</div>



-->

        
<div class="busuanzi-count">
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

  
    <span class="site-uv">
      <i class="fa fa-user"></i> 访问人数
      <span class="busuanzi-value" id="busuanzi_value_site_uv"></span>
      
    </span>
  

  
    <span class="site-pv">
      <i class="fa fa-eye"></i> 总访问量
      <span class="busuanzi-value" id="busuanzi_value_site_pv"></span>
      
    </span>
  
</div>








        
      </div>
    </footer>

    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.4"></script>



  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script>



  


  

    
      <script id="dsq-count-scr" src="https://true.disqus.com/count.js" async></script>
    

    
      <script type="text/javascript">
        var disqus_config = function () {
          this.page.url = 'https://xczhello.gitee.io/uncategorized/imooc-frontend-interview/7. 跨域通信类.html/';
          this.page.identifier = 'uncategorized/imooc-frontend-interview/7. 跨域通信类.html/';
          this.page.title = '';
        };
        var d = document, s = d.createElement('script');
        s.src = 'https://true.disqus.com/embed.js';
        s.setAttribute('data-timestamp', '' + +new Date());
        (d.head || d.body).appendChild(s);
      </script>
    

  




	





  














  

  <script type="text/javascript">
    // Popup Window;
    var isfetched = false;
    var isXml = true;
    // Search DB path;
    var search_path = "search.xml";
    if (search_path.length === 0) {
      search_path = "search.xml";
    } else if (/json$/i.test(search_path)) {
      isXml = false;
    }
    var path = "/" + search_path;
    // monitor main search box;

    var onPopupClose = function (e) {
      $('.popup').hide();
      $('#local-search-input').val('');
      $('.search-result-list').remove();
      $('#no-result').remove();
      $(".local-search-pop-overlay").remove();
      $('body').css('overflow', '');
    }

    function proceedsearch() {
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay"></div>')
        .css('overflow', 'hidden');
      $('.search-popup-overlay').click(onPopupClose);
      $('.popup').toggle();
      var $localSearchInput = $('#local-search-input');
      $localSearchInput.attr("autocapitalize", "none");
      $localSearchInput.attr("autocorrect", "off");
      $localSearchInput.focus();
    }

    // search function;
    var searchFunc = function(path, search_id, content_id) {
      'use strict';

      // start loading animation
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay">' +
          '<div id="search-loading-icon">' +
          '<i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>' +
          '</div>' +
          '</div>')
        .css('overflow', 'hidden');
      $("#search-loading-icon").css('margin', '20% auto 0 auto').css('text-align', 'center');

      $.ajax({
        url: path,
        dataType: isXml ? "xml" : "json",
        async: true,
        success: function(res) {
          // get the contents from search data
          isfetched = true;
          $('.popup').detach().appendTo('.header-inner');
          var datas = isXml ? $("entry", res).map(function() {
            return {
              title: $("title", this).text(),
              content: $("content",this).text(),
              url: $("url" , this).text()
            };
          }).get() : res;
          var input = document.getElementById(search_id);
          var resultContent = document.getElementById(content_id);
          var inputEventFunction = function() {
            var searchText = input.value.trim().toLowerCase();
            var keywords = searchText.split(/[\s\-]+/);
            if (keywords.length > 1) {
              keywords.push(searchText);
            }
            var resultItems = [];
            if (searchText.length > 0) {
              // perform local searching
              datas.forEach(function(data) {
                var isMatch = false;
                var hitCount = 0;
                var searchTextCount = 0;
                var title = data.title.trim();
                var titleInLowerCase = title.toLowerCase();
                var content = data.content.trim().replace(/<[^>]+>/g,"");
                var contentInLowerCase = content.toLowerCase();
                var articleUrl = decodeURIComponent(data.url);
                var indexOfTitle = [];
                var indexOfContent = [];
                // only match articles with not empty titles
                if(title != '') {
                  keywords.forEach(function(keyword) {
                    function getIndexByWord(word, text, caseSensitive) {
                      var wordLen = word.length;
                      if (wordLen === 0) {
                        return [];
                      }
                      var startPosition = 0, position = [], index = [];
                      if (!caseSensitive) {
                        text = text.toLowerCase();
                        word = word.toLowerCase();
                      }
                      while ((position = text.indexOf(word, startPosition)) > -1) {
                        index.push({position: position, word: word});
                        startPosition = position + wordLen;
                      }
                      return index;
                    }

                    indexOfTitle = indexOfTitle.concat(getIndexByWord(keyword, titleInLowerCase, false));
                    indexOfContent = indexOfContent.concat(getIndexByWord(keyword, contentInLowerCase, false));
                  });
                  if (indexOfTitle.length > 0 || indexOfContent.length > 0) {
                    isMatch = true;
                    hitCount = indexOfTitle.length + indexOfContent.length;
                  }
                }

                // show search results

                if (isMatch) {
                  // sort index by position of keyword

                  [indexOfTitle, indexOfContent].forEach(function (index) {
                    index.sort(function (itemLeft, itemRight) {
                      if (itemRight.position !== itemLeft.position) {
                        return itemRight.position - itemLeft.position;
                      } else {
                        return itemLeft.word.length - itemRight.word.length;
                      }
                    });
                  });

                  // merge hits into slices

                  function mergeIntoSlice(text, start, end, index) {
                    var item = index[index.length - 1];
                    var position = item.position;
                    var word = item.word;
                    var hits = [];
                    var searchTextCountInSlice = 0;
                    while (position + word.length <= end && index.length != 0) {
                      if (word === searchText) {
                        searchTextCountInSlice++;
                      }
                      hits.push({position: position, length: word.length});
                      var wordEnd = position + word.length;

                      // move to next position of hit

                      index.pop();
                      while (index.length != 0) {
                        item = index[index.length - 1];
                        position = item.position;
                        word = item.word;
                        if (wordEnd > position) {
                          index.pop();
                        } else {
                          break;
                        }
                      }
                    }
                    searchTextCount += searchTextCountInSlice;
                    return {
                      hits: hits,
                      start: start,
                      end: end,
                      searchTextCount: searchTextCountInSlice
                    };
                  }

                  var slicesOfTitle = [];
                  if (indexOfTitle.length != 0) {
                    slicesOfTitle.push(mergeIntoSlice(title, 0, title.length, indexOfTitle));
                  }

                  var slicesOfContent = [];
                  while (indexOfContent.length != 0) {
                    var item = indexOfContent[indexOfContent.length - 1];
                    var position = item.position;
                    var word = item.word;
                    // cut out 100 characters
                    var start = position - 20;
                    var end = position + 80;
                    if(start < 0){
                      start = 0;
                    }
                    if (end < position + word.length) {
                      end = position + word.length;
                    }
                    if(end > content.length){
                      end = content.length;
                    }
                    slicesOfContent.push(mergeIntoSlice(content, start, end, indexOfContent));
                  }

                  // sort slices in content by search text's count and hits' count

                  slicesOfContent.sort(function (sliceLeft, sliceRight) {
                    if (sliceLeft.searchTextCount !== sliceRight.searchTextCount) {
                      return sliceRight.searchTextCount - sliceLeft.searchTextCount;
                    } else if (sliceLeft.hits.length !== sliceRight.hits.length) {
                      return sliceRight.hits.length - sliceLeft.hits.length;
                    } else {
                      return sliceLeft.start - sliceRight.start;
                    }
                  });

                  // select top N slices in content

                  var upperBound = parseInt('1');
                  if (upperBound >= 0) {
                    slicesOfContent = slicesOfContent.slice(0, upperBound);
                  }

                  // highlight title and content

                  function highlightKeyword(text, slice) {
                    var result = '';
                    var prevEnd = slice.start;
                    slice.hits.forEach(function (hit) {
                      result += text.substring(prevEnd, hit.position);
                      var end = hit.position + hit.length;
                      result += '<b class="search-keyword">' + text.substring(hit.position, end) + '</b>';
                      prevEnd = end;
                    });
                    result += text.substring(prevEnd, slice.end);
                    return result;
                  }

                  var resultItem = '';

                  if (slicesOfTitle.length != 0) {
                    resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + highlightKeyword(title, slicesOfTitle[0]) + "</a>";
                  } else {
                    resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + title + "</a>";
                  }

                  slicesOfContent.forEach(function (slice) {
                    resultItem += "<a href='" + articleUrl + "'>" +
                      "<p class=\"search-result\">" + highlightKeyword(content, slice) +
                      "...</p>" + "</a>";
                  });

                  resultItem += "</li>";
                  resultItems.push({
                    item: resultItem,
                    searchTextCount: searchTextCount,
                    hitCount: hitCount,
                    id: resultItems.length
                  });
                }
              })
            };
            if (keywords.length === 1 && keywords[0] === "") {
              resultContent.innerHTML = '<div id="no-result"><i class="fa fa-search fa-5x" /></div>'
            } else if (resultItems.length === 0) {
              resultContent.innerHTML = '<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>'
            } else {
              resultItems.sort(function (resultLeft, resultRight) {
                if (resultLeft.searchTextCount !== resultRight.searchTextCount) {
                  return resultRight.searchTextCount - resultLeft.searchTextCount;
                } else if (resultLeft.hitCount !== resultRight.hitCount) {
                  return resultRight.hitCount - resultLeft.hitCount;
                } else {
                  return resultRight.id - resultLeft.id;
                }
              });
              var searchResultList = '<ul class=\"search-result-list\">';
              resultItems.forEach(function (result) {
                searchResultList += result.item;
              })
              searchResultList += "</ul>";
              resultContent.innerHTML = searchResultList;
            }
          }

          if ('auto' === 'auto') {
            input.addEventListener('input', inputEventFunction);
          } else {
            $('.search-icon').click(inputEventFunction);
            input.addEventListener('keypress', function (event) {
              if (event.keyCode === 13) {
                inputEventFunction();
              }
            });
          }

          // remove loading animation
          $(".local-search-pop-overlay").remove();
          $('body').css('overflow', '');

          proceedsearch();
        }
      });
    }

    // handle and trigger popup window;
    $('.popup-trigger').click(function(e) {
      e.stopPropagation();
      if (isfetched === false) {
        searchFunc(path, 'local-search-input', 'local-search-result');
      } else {
        proceedsearch();
      };
    });

    $('.popup-btn-close').click(onPopupClose);
    $('.popup').click(function(e){
      e.stopPropagation();
    });
    $(document).on('keyup', function (event) {
      var shouldDismissSearchPopup = event.which === 27 &&
        $('.search-popup').is(':visible');
      if (shouldDismissSearchPopup) {
        onPopupClose();
      }
    });
  </script>





  

  

  

  
  
  
  <link rel="stylesheet" href="/lib/needsharebutton/needsharebutton.css">

  
  
  <script src="/lib/needsharebutton/needsharebutton.js"></script>

  <script>
    
      pbOptions = {};
      
          pbOptions.iconStyle = "box";
      
          pbOptions.boxForm = "horizontal";
      
          pbOptions.position = "bottomCenter";
      
          pbOptions.networks = "Weibo,Wechat,Douban,QQZone,Twitter,Facebook,GooglePlus,Linkedin,Evernote";
      
      new needShareButton('#needsharebutton-postbottom', pbOptions);
    
    
  </script>

  

  

  

  

  <!-- 页面点击小红心 -->
  <script type="text/javascript" src="/js/src/click.js"></script>
  <!-- 背景动画 -->
  <script type="text/javascript" src="/js/src/particle.js"></script>
<script src="/live2dw/lib/L2Dwidget.min.js?0c58a1486de42ac6cc1c59c7d98ae887"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","tagMode":false,"debug":false,"model":{"jsonPath":"/live2dw/assets/tororo.model.json"},"display":{"position":"right","width":120,"height":240},"mobile":{"show":true},"log":false});</script></body>
</html>
